package com.ushine.web.aop;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/**
 * @Author yls
 * @Date 2020/4/14 10:41
 * @Description 切面类，监控当前切面的类的方法执行情况
 * 监控系统模块：用户、权限、等模块
 * @Version 1.0
 **/
@Aspect
@Component
@Slf4j
public class AppContainerAspect {

    /**
     * 扫描所有的【Controller】
     */
    private static final String BASE_CONTROLLER_AOP = "execution(* com.ushine.web.base..*Controller.*(..))";
    /**
     * 扫描所有的【Service】
     */
    private static final String BASE_SERVICE_AOP = "execution(* com.ushine.web.base..*ServiceImpl.*(..))";
    /**
     * 扫描所有的【FacadeImpl】
     */
    private static final String BASE_FACADE_SERVICE_AOP = "execution(* com.ushine.web.base..*FacadeImpl.*(..))";


    /**
     * 功能描述:
     * 〈设置切面的切入点，主要是设置哪些类和方法需要使用切面编程〉
     *
     * @return : void
     * @author : yls
     * @date : 2020/07/12 10:29
     */
    @Pointcut(BASE_CONTROLLER_AOP + "||" + BASE_SERVICE_AOP + "||" + BASE_FACADE_SERVICE_AOP)
    public void appContainerAspect() {
        // 定义切点
    }

    /**
     * 功能描述:
     * 〈前置通知：在方法执行之前执行该通知，通知用户该方法开始执行〉
     *
     * @param joinPoint 切入点
     * @return : void
     * @author : yls
     * @date : 2020/07/12 10:30
     */
    @Before(value = "appContainerAspect()")
    public void before(JoinPoint joinPoint) {
        String name = joinPoint.getSignature().getName();
        log.info(name + "方法开始执行....");
    }

    /**
     * 功能描述:
     * 〈后置通知：在方法执行之后执行该通知，通知用户该方法已经执行完成〉
     *
     * @param joinPoint 切入点
     * @return : void
     * @author : yls
     * @date : 2020/07/12 10:31
     */
    @After(value = "appContainerAspect()")
    public void after(JoinPoint joinPoint) {
        String name = joinPoint.getSignature().getName();
        log.info("{}方法执行结束....", name);
    }


    /**
     * 功能描述:
     * 〈异常通知：在方法执行出现异常时执行该通知，通知用户该方法出现了某种异常〉
     *
     * @param joinPoint 代理链
     * @param e         异常
     * @return void
     * @Author yls
     * @Date 2020/3/30 17:17
     **/
    @AfterThrowing(value = "appContainerAspect()", throwing = "e")
    public void afterThrowing(JoinPoint joinPoint, Exception e) {
        String name = joinPoint.getSignature().getName();
        log.info("{}方法抛出异常，异常是：{}", name, e);
    }

    /**
     * 功能描述:
     * 〈环绕通知：可以监控方法从开始到结束的执行情况〉
     *
     * @param pjq 代理链执行
     * @return java.lang.Object
     * @Author yls
     * @Date 2020/3/30 17:17
     **/
    @Around(value = "appContainerAspect()")
    public Object around(ProceedingJoinPoint pjq) throws Throwable {
        // 执行的方法名
        String name = pjq.getSignature().toString();
        // 开始执行时间
        long startTime = System.currentTimeMillis();
        // 执行具体的业务逻辑
        Object proceed = pjq.proceed();
        // 方法执行结束时间
        long endTime = System.currentTimeMillis();
        log.info("{}执行的耗费时间{}/ms", name, (endTime - startTime));
        return proceed;
    }
}
